SPB Git forge
3commits 1branches 0releases
417.0 KBsize
maindefault branch
10 days agolast push
TypeScript 66.5% Python 30.9% JavaScript 1.4% CSS 0.7%
1.5 KB · 28 lines typescript
Raw Blame History
1import { NextResponse } from 'next/server';2import type { ReviewDecision } from '@/components/admin/types';3import { adminApi, AdminApiError } from '@/lib/admin-api';4import { isAdmin } from '@/lib/admin-auth';56export const dynamic = 'force-dynamic';78const DECISIONS: ReviewDecision[] = ['merged', 'kept_separate', 'dismissed'];910/** Entity-resolution decision: body `{ "decision": "merged" | "kept_separate" | "dismissed" }`. Merges are audited server-side (entity_merges). */11export async function POST(req: Request, ctx: { params: Promise<{ id: string }> }): Promise<Response> {12  if (!(await isAdmin())) return NextResponse.json({ error: { title: 'Unauthorized', status: 401 } }, { status: 401 });13  const { id } = await ctx.params;14  const itemId = Number(id);15  const body = (await req.json().catch(() => null)) as { decision?: unknown } | null;16  const decision = body?.decision;17  if (!Number.isInteger(itemId) || typeof decision !== 'string' || !DECISIONS.includes(decision as ReviewDecision)) {18    return NextResponse.json({ error: { title: 'Invalid request', detail: 'decision must be merged | kept_separate | dismissed', status: 422 } }, { status: 422 });19  }20  try {21    const out = await adminApi.decide(itemId, decision as ReviewDecision, 'admin-web');22    return NextResponse.json(out.data);23  } catch (e) {24    const status = e instanceof AdminApiError && e.status > 0 ? e.status : 502;25    return NextResponse.json({ error: { title: 'Decision failed', detail: (e as Error).message, status } }, { status });26  }27}28